package com.htht.job.admin.core.trigger;


import com.htht.job.admin.core.enums.ExecutorFailStrategyEnum;
import com.htht.job.admin.core.model.XxlJobGroup;
import com.htht.job.admin.core.model.XxlJobInfo;
import com.htht.job.admin.core.model.XxlJobLog;
import com.htht.job.admin.core.route.ExecutorRouteStrategyEnum;
import com.htht.job.admin.core.route.strategy.ExecutorRouteRandom;
import com.htht.job.admin.core.schedule.XxlJobDynamicScheduler;
import com.htht.job.admin.core.thread.JobFailMonitorHelper;
import com.htht.job.admin.core.util.SpringContextUtil;
import com.htht.job.core.api.DubboService;
import com.htht.job.core.api.parameter.JobParameterService;
import com.htht.job.core.biz.ExecutorBiz;
import com.htht.job.core.biz.model.ReturnT;
import com.htht.job.core.biz.model.TriggerParam;
import com.htht.job.core.enums.ExecutorBlockStrategyEnum;
import com.htht.job.core.util.ResultUtil;
import com.htht.job.executor.model.parameter.JobParameterModel;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * xxl-job trigger
 * Created by xuxueli on 17/7/13.
 */

public class XxlJobTrigger  {
    private static Logger logger = LoggerFactory.getLogger(XxlJobTrigger.class);

	/**
     * trigger job
     *
     * @param jobId
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
	public static void trigger(int jobId){

        // load data
        XxlJobInfo jobInfo = XxlJobDynamicScheduler.xxlJobInfoDao.loadById(jobId);              // job info
        if (jobInfo == null) {
            logger.warn(">>>>>>>>>>>> trigger fail, jobId invalid，jobId={}", jobId);
            return;
        }
        JobParameterService jobParameterService = (JobParameterService)SpringContextUtil.getBean("jobParameterService");
        Map fixmap=jobParameterService.getJobParameter(jobInfo.getExecutorParam(), jobInfo.getModelId(), "1");
        Map dymap=jobParameterService.getJobParameter(jobInfo.getExecutorParam(), jobInfo.getModelId(), "2");
        JobParameterModel jobParameterModel=jobParameterService.findJobParameterById(jobInfo.getExecutorParam());
        String modelParameters=jobParameterModel.getModelParameters();
        XxlJobGroup group = XxlJobDynamicScheduler.xxlJobGroupDao.load(jobInfo.getJobGroup());  // group info

        ExecutorBlockStrategyEnum blockStrategy = ExecutorBlockStrategyEnum.match(jobInfo.getExecutorBlockStrategy(), ExecutorBlockStrategyEnum.SERIAL_EXECUTION);  // block strategy
        ExecutorFailStrategyEnum failStrategy = ExecutorFailStrategyEnum.match(jobInfo.getExecutorFailStrategy(), ExecutorFailStrategyEnum.FAIL_ALARM);    // fail strategy
        ExecutorRouteStrategyEnum executorRouteStrategyEnum = ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null);    // route strategy
        ArrayList<String> addressList = (ArrayList<String>) group.getRegistryList();

        // broadcast
        if (ExecutorRouteStrategyEnum.SHARDING_BROADCAST == executorRouteStrategyEnum && CollectionUtils.isNotEmpty(addressList)) {
                 DubboService dubboService = (DubboService)SpringContextUtil.getBean("dubboService");
        	     List<String> list=new ArrayList<String>();
        	     ResultUtil<List<String>> result=dubboService.execute(modelParameters,jobInfo.getExecutorHandler(),fixmap,dymap);
        	     list=result.getResult();
        		for (int i = 0; i < list.size(); i++){
        			XxlJobLog jobLog = new XxlJobLog();
        	        jobLog.setJobGroup(jobInfo.getJobGroup());
        	        jobLog.setJobId(jobInfo.getId());
        	        XxlJobDynamicScheduler.xxlJobLogDao.save(jobLog);
        	        logger.debug(">>>>>>>>>>> xxl-job trigger start, jobId:{}", jobLog.getId());

        	        // 2、prepare trigger-info
        	        //jobLog.setExecutorAddress(executorAddress);
        	        jobLog.setGlueType(jobInfo.getGlueType());
        	        jobLog.setExecutorHandler(jobInfo.getExecutorHandler());
        	        jobLog.setExecutorParam(jobInfo.getExecutorParam());
        	        jobLog.setTriggerTime(new Date());

        	        ReturnT<String> triggerResult = new ReturnT<String>(null);
        	        StringBuffer triggerMsgSb = new StringBuffer();
        	        triggerMsgSb.append("注册方式：").append( (group.getAddressType() == 0)?"自动注册":"手动录入" );
        	        triggerMsgSb.append("<br>阻塞处理策略：").append(blockStrategy.getTitle());
        	        triggerMsgSb.append("<br>失败处理策略：").append(failStrategy.getTitle());
        	        triggerMsgSb.append("<br>地址列表：").append(group.getRegistryList());
        	        triggerMsgSb.append("<br>路由策略：").append(executorRouteStrategyEnum.getTitle());

        	        // 3、trigger-valid
        	        if (triggerResult.getCode()==ReturnT.SUCCESS_CODE && CollectionUtils.isEmpty(addressList)) {
        	            triggerResult.setCode(ReturnT.FAIL_CODE);
        	            triggerMsgSb.append("<br>----------------------<br>").append("调度失败：").append("执行器地址为空");
        	        }

        	        if (triggerResult.getCode() == ReturnT.SUCCESS_CODE) {

        	            // 4.1、trigger-param
        	            TriggerParam triggerParam = new TriggerParam();
        	            triggerParam.setJobId(jobInfo.getId());
        	            triggerParam.setExecutorHandler(jobInfo.getExecutorHandler());
        	            triggerParam.setExecutorParams(list.get(i));
        	            triggerParam.setExecutorBlockStrategy(jobInfo.getExecutorBlockStrategy());
        	            triggerParam.setLogId(jobLog.getId());
        	            triggerParam.setLogDateTim(jobLog.getTriggerTime().getTime());
        	            triggerParam.setGlueType(jobInfo.getGlueType());
        	            triggerParam.setGlueSource(jobInfo.getGlueSource());
        	            triggerParam.setGlueUpdatetime(jobInfo.getGlueUpdatetime().getTime());
        	            triggerParam.setBroadcastIndex(0);
        	            triggerParam.setBroadcastTotal(1);
                        triggerParam.setModelParameters(modelParameters);
                        triggerParam.setFixedParameter(fixmap);
                        triggerParam.setDynamicParameter(dymap);
                        triggerParam.setModelId(jobInfo.getModelId());
                        triggerParam.setProductId(jobInfo.getProductId());
                        // 4.2、trigger-run (route run / trigger remote executor)
        	            triggerResult =new ExecutorRouteRandom().routeRun(triggerParam, addressList);
        	            triggerMsgSb.append("<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>").append(triggerResult.getMsg());

        	            // 4.3、trigger (fail retry)
        	            if (triggerResult.getCode()!=ReturnT.SUCCESS_CODE && failStrategy == ExecutorFailStrategyEnum.FAIL_RETRY) {
        	                triggerResult = new ExecutorRouteRandom().routeRun(triggerParam, addressList);
        	                triggerMsgSb.append("<br><br><span style=\"color:#F39C12;\" > >>>>>>>>>>>失败重试<<<<<<<<<<< </span><br>").append(triggerResult.getMsg());
        	            }
        	        }

        	        // 5、save trigger-info
        	        jobLog.setExecutorAddress(triggerResult.getContent());
        	        jobLog.setTriggerCode(triggerResult.getCode());
        	        jobLog.setTriggerMsg(triggerMsgSb.toString());
        	        XxlJobDynamicScheduler.xxlJobLogDao.updateTriggerInfo(jobLog);

        	        // 6、monitor triger
        	        JobFailMonitorHelper.monitor(jobLog.getId());
        	        logger.debug(">>>>>>>>>>> xxl-job trigger end, jobId:{}", jobLog.getId());

        		}
        		 return;
        	}

     

        // 1、save log-id
        XxlJobLog jobLog = new XxlJobLog();
        jobLog.setJobGroup(jobInfo.getJobGroup());
        jobLog.setJobId(jobInfo.getId());
        XxlJobDynamicScheduler.xxlJobLogDao.save(jobLog);
        logger.debug(">>>>>>>>>>> xxl-job trigger start, jobId:{}", jobLog.getId());

        // 2、prepare trigger-info
        //jobLog.setExecutorAddress(executorAddress);
        jobLog.setGlueType(jobInfo.getGlueType());
        jobLog.setExecutorHandler(jobInfo.getExecutorHandler());
        jobLog.setExecutorParam(jobInfo.getExecutorParam());
        jobLog.setTriggerTime(new Date());

        ReturnT<String> triggerResult = new ReturnT<String>(null);
        StringBuffer triggerMsgSb = new StringBuffer();
        triggerMsgSb.append("注册方式：").append( (group.getAddressType() == 0)?"自动注册":"手动录入" );
        triggerMsgSb.append("<br>阻塞处理策略：").append(blockStrategy.getTitle());
        triggerMsgSb.append("<br>失败处理策略：").append(failStrategy.getTitle());
        triggerMsgSb.append("<br>地址列表：").append(group.getRegistryList());
        triggerMsgSb.append("<br>路由策略：").append(executorRouteStrategyEnum.getTitle());

        // 3、trigger-valid
        if (triggerResult.getCode()==ReturnT.SUCCESS_CODE && CollectionUtils.isEmpty(addressList)) {
            triggerResult.setCode(ReturnT.FAIL_CODE);
            triggerMsgSb.append("<br>----------------------<br>").append("调度失败：").append("执行器地址为空");
        }

        if (triggerResult.getCode() == ReturnT.SUCCESS_CODE) {
            // 4.1、trigger-param
            TriggerParam triggerParam = new TriggerParam();
            triggerParam.setJobId(jobInfo.getId());
            triggerParam.setExecutorHandler(jobInfo.getExecutorHandler());
            triggerParam.setExecutorParams("");
            triggerParam.setExecutorBlockStrategy(jobInfo.getExecutorBlockStrategy());
            triggerParam.setLogId(jobLog.getId());
            triggerParam.setLogDateTim(jobLog.getTriggerTime().getTime());
            triggerParam.setGlueType(jobInfo.getGlueType());
            triggerParam.setGlueSource(jobInfo.getGlueSource());
            triggerParam.setGlueUpdatetime(jobInfo.getGlueUpdatetime().getTime());
            triggerParam.setBroadcastIndex(0);
            triggerParam.setBroadcastTotal(1);
            triggerParam.setFixedParameter(fixmap);
            triggerParam.setDynamicParameter(dymap);
            triggerParam.setModelParameters(modelParameters);
            triggerParam.setModelId(jobInfo.getModelId());
            triggerParam.setProductId(jobInfo.getProductId());

            // 4.2、trigger-run (route run / trigger remote executor)
            triggerResult = executorRouteStrategyEnum.getRouter().routeRun(triggerParam, addressList);
            triggerMsgSb.append("<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>").append(triggerResult.getMsg());

            // 4.3、trigger (fail retry)
            if (triggerResult.getCode()!=ReturnT.SUCCESS_CODE && failStrategy == ExecutorFailStrategyEnum.FAIL_RETRY) {
                triggerResult = executorRouteStrategyEnum.getRouter().routeRun(triggerParam, addressList);
                triggerMsgSb.append("<br><br><span style=\"color:#F39C12;\" > >>>>>>>>>>>失败重试<<<<<<<<<<< </span><br>").append(triggerResult.getMsg());
            }
        }

        // 5、save trigger-info
        jobLog.setExecutorAddress(triggerResult.getContent());
        jobLog.setTriggerCode(triggerResult.getCode());
        jobLog.setTriggerMsg(triggerMsgSb.toString());
        XxlJobDynamicScheduler.xxlJobLogDao.updateTriggerInfo(jobLog);

        // 6、monitor triger
        JobFailMonitorHelper.monitor(jobLog.getId());
        logger.debug(">>>>>>>>>>> xxl-job trigger end, jobId:{}", jobLog.getId());
    }

    /**
     * run executor
     * @param triggerParam
     * @param address
     * @return  ReturnT.content: final address
     */
    public static ReturnT<String> runExecutor(TriggerParam triggerParam, String address){
        ReturnT<String> runResult = null;
        try {
            ExecutorBiz executorBiz = XxlJobDynamicScheduler.getExecutorBiz(address);
            runResult = executorBiz.run(triggerParam);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            runResult = new ReturnT<String>(ReturnT.FAIL_CODE, ""+e );
        }

        StringBuffer runResultSB = new StringBuffer("触发调度：");
        runResultSB.append("<br>address：").append(address);
        runResultSB.append("<br>code：").append(runResult.getCode());
        runResultSB.append("<br>msg：").append(runResult.getMsg());

        runResult.setMsg(runResultSB.toString());
        runResult.setContent(address);
        return runResult;
    }



}
